#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import re
import time
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, scrolledtext
from docx import Document
from docx.shared import Pt
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
from pypinyin import pinyin, Style
import pyttsx3
import threading

class WordPinyin:
    def __init__(self):
        # 初始化拼音处理类
        pass
    
    def is_chinese_char(self, char):
        """判断字符是否为中文字符"""
        return '\u4e00' <= char <= '\u9fff'

    def add_pinyin_to_char(self, run, char, pinyin_text, pinyin_font='SimSun'):
        """为单个汉字添加注音"""
        if not pinyin_text:
            run.text = char
            return
        
        # 创建一个新的字段（field）用于显示注音
        fld_char_begin = OxmlElement('w:fldChar')
        fld_char_begin.set(qn('w:fldCharType'), 'begin')
        
        instr_text = OxmlElement('w:instrText')
        # 设置EQ域代码，用于显示注音
        instr_text.text = f' EQ \\* jc0 \\* "Font:{pinyin_font}" \\* hps14 \\o \\ad(\\s \\up 13({pinyin_text}),{char})'
        
        fld_char_separate = OxmlElement('w:fldChar')
        fld_char_separate.set(qn('w:fldCharType'), 'separate')
        
        fld_char_end = OxmlElement('w:fldChar')
        fld_char_end.set(qn('w:fldCharType'), 'end')
        
        # 清除原run的文本
        run.text = ''
        
        # 将字段添加到run中
        run._r.append(fld_char_begin)
        run._r.append(instr_text)
        run._r.append(fld_char_separate)
        run._r.append(fld_char_end)
    
    def get_text_with_pinyin(self, text):
        """获取文本的拼音预览，返回文本和拼音的映射列表"""
        result = []
        pinyin_list = pinyin(text, heteronym=True, errors='ignore')
        pyl_i = 0
        
        for char in text:
            if self.is_chinese_char(char):
                # 获取多音字的所有可能拼音
                all_pinyins = pinyin_list[pyl_i]
                result.append({
                    'char': char,
                    'is_chinese': True,
                    'pinyins': all_pinyins,
                    'selected_pinyin': all_pinyins[0] if all_pinyins else ''
                })
                pyl_i += 1
            else:
                result.append({
                    'char': char,
                    'is_chinese': False,
                    'pinyins': [],
                    'selected_pinyin': ''
                })
        
        return result
    
    def process_document(self, input_file, output_file=None, custom_pinyin_map=None, paragraph_styles=None):
        """处理Word文档，为汉字添加注音"""
        if not os.path.exists(input_file):
            raise FileNotFoundError(f"找不到文件: {input_file}")
        
        # 如果未指定输出文件，则在原文件名基础上加"_with_pinyin"后缀
        if output_file is None:
            base_name, ext = os.path.splitext(input_file)
            output_file = f"{base_name}_with_pinyin{ext}"
        
        # 打开文档
        doc = Document(input_file)
        
        # 收集所有中文字符信息，用于生成与UI一致的字符ID
        all_chars_list = []
        
        # 第一次遍历：收集所有中文字符信息
        for paragraph in doc.paragraphs:
            for run in paragraph.runs:
                text = run.text
                text_with_pinyin = self.get_text_with_pinyin(text)
                for item in text_with_pinyin:
                    if item['is_chinese']:
                        all_chars_list.append(item['char'])
        
        # 第二次遍历：处理文档并添加拼音
        char_index = 0  # 用于生成与UI一致的字符ID
        
        for i, paragraph in enumerate(doc.paragraphs):
            # 保存原始段落的样式
            original_style = paragraph.style
            
            # 保存原始段落中的所有run
            original_runs = list(paragraph.runs)
            
            # 清空段落
            paragraph.clear()
            
            # 重新设置段落样式
            paragraph.style = original_style
            
            # 应用自定义段落样式
            if paragraph_styles and i in paragraph_styles:
                style = paragraph_styles[i]
                if 'font_name' in style:
                    for run in paragraph.runs:
                        run.font.name = style['font_name']
                if 'font_size' in style:
                    for run in paragraph.runs:
                        run.font.size = Pt(style['font_size'])
                if 'font_bold' in style:
                    for run in paragraph.runs:
                        run.font.bold = style['font_bold']
                if 'font_italic' in style:
                    for run in paragraph.runs:
                        run.font.italic = style['font_italic']
                if 'font_underline' in style:
                    for run in paragraph.runs:
                        run.font.underline = style['font_underline']
            
            # 处理每个run
            for run in original_runs:
                # 获取原始run的文本、字体、大小等属性
                text = run.text
                font_name = run.font.name
                font_size = run.font.size
                font_bold = run.font.bold
                font_italic = run.font.italic
                font_underline = run.font.underline
                
                # 获取文本的拼音信息
                text_with_pinyin = self.get_text_with_pinyin(text)
                
                # 遍历文本中的每个字符
                for item in text_with_pinyin:
                    # 创建新的run
                    new_run = paragraph.add_run()
                    # 复制原始run的属性
                    if font_name:
                        new_run.font.name = font_name
                    if font_size:
                        new_run.font.size = font_size
                    new_run.font.bold = font_bold
                    new_run.font.italic = font_italic
                    new_run.font.underline = font_underline
                    
                    # 为中文字符添加注音
                    if item['is_chinese']:
                        # 使用与UI界面一致的字符ID生成逻辑
                        # 这里char_index与UI中的i保持一致
                        char_id = f"{item['char']}_{char_index}"
                        char_index += 1
                        
                        # 检查是否有自定义拼音映射
                        # 首先检查字符ID的映射
                        if custom_pinyin_map and char_id in custom_pinyin_map:
                            self.add_pinyin_to_char(new_run, item['char'], custom_pinyin_map[char_id], font_name)
                        # 然后检查字符本身的映射
                        elif custom_pinyin_map and item['char'] in custom_pinyin_map:
                            self.add_pinyin_to_char(new_run, item['char'], custom_pinyin_map[item['char']], font_name)
                        else:
                            self.add_pinyin_to_char(new_run, item['char'], item['selected_pinyin'], font_name)
                    else:
                        new_run.text = item['char']
        
        # 保存文档
        doc.save(output_file)
        print(f"已成功添加注音并保存至: {output_file}")
        return output_file

class PinyinApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Word文档拼音标注工具")
        self.root.geometry("1000x700")
        
        # 初始化WordPinyin实例
        self.wp = WordPinyin()
        
        # 文件路径
        self.input_file = ""
        self.output_file = ""
        
        # 自定义拼音映射
        self.custom_pinyin_map = {}
        
        # 自定义段落样式
        self.paragraph_styles = {}
        
        # 当前选中的字符
        self.current_char = ""
        
        # 当前选中的段落索引
        self.current_paragraph_index = -1
        
        # 拼音播放相关属性
        self.engine = pyttsx3.init()
        self.is_playing = False
        self.current_play_index = 0
        self.play_thread = None
        
        # 创建UI
        self.create_ui()
    
    def create_ui(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建顶部操作区
        top_frame = ttk.Frame(main_frame, padding="5")
        top_frame.pack(fill=tk.X, pady=5)
        
        # 选择文件按钮
        self.select_file_btn = ttk.Button(top_frame, text="选择Word文档", command=self.select_file)
        self.select_file_btn.pack(side=tk.LEFT, padx=5)
        
        # 文件路径显示
        self.file_path_var = tk.StringVar()
        self.file_path_var.set("未选择文件")
        self.file_path_label = ttk.Label(top_frame, textvariable=self.file_path_var, width=80)
        self.file_path_label.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 处理文件按钮
        self.process_file_btn = ttk.Button(top_frame, text="处理文档", command=self.process_file, state=tk.DISABLED)
        self.process_file_btn.pack(side=tk.RIGHT, padx=5)
        
        # 创建预览区域
        preview_frame = ttk.LabelFrame(main_frame, text="拼音预览", padding="5")
        preview_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 创建Tab控件
        self.tab_control = ttk.Notebook(preview_frame)
        
        # 段落列表Tab
        self.paragraphs_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.paragraphs_tab, text="段落列表")
        
        # 多音字修改Tab
        self.polyphone_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.polyphone_tab, text="多音字修改")
        
        # 段落样式修改Tab
        self.style_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.style_tab, text="段落样式")
        
        self.tab_control.pack(fill=tk.BOTH, expand=True)
        
        # 初始化段落列表
        self.init_paragraphs_tab()
        
        # 初始化多音字修改Tab
        self.init_polyphone_tab()
        
        # 初始化段落样式Tab
        self.init_style_tab()
    
    def init_paragraphs_tab(self):
        # 创建滚动文本框显示段落
        self.paragraphs_text = scrolledtext.ScrolledText(self.paragraphs_tab, wrap=tk.WORD, font=("SimHei", 10))
        self.paragraphs_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 创建底部操作按钮
        btn_frame = ttk.Frame(self.paragraphs_tab, padding="5")
        btn_frame.pack(fill=tk.X, pady=5)
        
        self.preview_btn = ttk.Button(btn_frame, text="预览拼音", command=self.preview_pinyin, state=tk.DISABLED)
        self.preview_btn.pack(side=tk.RIGHT, padx=5)
    
    def init_polyphone_tab(self):
        # 创建左侧列表
        left_frame = ttk.Frame(self.polyphone_tab, padding="5")
        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        ttk.Label(left_frame, text="所有字符列表:").pack(anchor=tk.W, pady=5)
        
        # 创建字符单选框的滚动区域
        self.char_frame = ttk.Frame(left_frame)
        self.char_frame.pack(fill=tk.BOTH, expand=True)
        
        self.char_canvas = tk.Canvas(self.char_frame)
        self.char_scrollbar = ttk.Scrollbar(self.char_frame, orient="vertical", command=self.char_canvas.yview)
        self.char_canvas.configure(yscrollcommand=self.char_scrollbar.set)
        
        self.char_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.char_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        self.char_content_frame = ttk.Frame(self.char_canvas)
        self.char_canvas_window = self.char_canvas.create_window((0, 0), window=self.char_content_frame, anchor="nw")
        
        # 绑定事件以更新滚动条
        self.char_content_frame.bind("<Configure>", self.on_char_frame_configure)
        self.char_canvas.bind("<Configure>", self.on_char_canvas_configure)
        
        # 创建右侧修改区域
        right_frame = ttk.Frame(self.polyphone_tab, padding="5")
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        
        # 拼音选择区域
        pinyin_frame = ttk.LabelFrame(right_frame, text="拼音设置", padding="5")
        pinyin_frame.pack(fill=tk.X, pady=5)
        
        # 拼音来源选择单选框
        ttk.Label(pinyin_frame, text="拼音来源:").grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.pinyin_source_var = tk.StringVar(value="preset")
        
        preset_rb = ttk.Radiobutton(pinyin_frame, text="预设拼音", variable=self.pinyin_source_var, value="preset")
        preset_rb.grid(row=0, column=1, sticky=tk.W, pady=5)
        
        custom_rb = ttk.Radiobutton(pinyin_frame, text="自定义拼音", variable=self.pinyin_source_var, value="custom")
        custom_rb.grid(row=0, column=2, sticky=tk.W, pady=5)
        
        # 推荐拼音
        ttk.Label(pinyin_frame, text="推荐拼音:").grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.pinyin_combobox = ttk.Combobox(pinyin_frame, font=("SimHei", 10))
        self.pinyin_combobox.grid(row=1, column=1, sticky=tk.W+tk.E, pady=5, padx=5, columnspan=2)
        
        # 自定义拼音
        ttk.Label(pinyin_frame, text="自定义拼音:").grid(row=2, column=0, sticky=tk.W, pady=5)
        
        self.custom_pinyin_entry = ttk.Entry(pinyin_frame, font=("SimHei", 10))
        self.custom_pinyin_entry.grid(row=2, column=1, sticky=tk.W+tk.E, pady=5, padx=5, columnspan=2)
        
        # 设置列权重，使输入框和下拉框可以扩展
        pinyin_frame.columnconfigure(1, weight=1)
        
        self.update_pinyin_btn = ttk.Button(right_frame, text="更新拼音", command=self.update_pinyin, state=tk.DISABLED)
        self.update_pinyin_btn.pack(side=tk.BOTTOM, pady=20)
        
        # 字符选择变量
        self.char_var = tk.StringVar()
        
        # 添加播放控制区域
        play_control_frame = ttk.LabelFrame(left_frame, text="拼音播放控制", padding="5")
        play_control_frame.pack(fill=tk.X, pady=5)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(play_control_frame, variable=self.progress_var, length=100)
        self.progress_bar.pack(fill=tk.X, pady=5)
        
        # 播放控制按钮
        control_btn_frame = ttk.Frame(play_control_frame)
        control_btn_frame.pack(fill=tk.X, pady=5)
        
        self.start_btn = ttk.Button(control_btn_frame, text="开始播放", command=self.start_playback)
        self.start_btn.pack(side=tk.LEFT, padx=5)
        
        self.pause_btn = ttk.Button(control_btn_frame, text="暂停播放", command=self.pause_playback, state=tk.DISABLED)
        self.pause_btn.pack(side=tk.LEFT, padx=5)
    
    def on_char_frame_configure(self, event):
        """更新字符框架的滚动区域"""
        self.char_canvas.configure(scrollregion=self.char_canvas.bbox("all"))
    
    def on_char_canvas_configure(self, event):
        """当画布大小变化时，调整内容窗口的宽度"""
        width = event.width
        self.char_canvas.itemconfig(self.char_canvas_window, width=width)
    
    def init_style_tab(self):
        # 创建左侧段落列表
        left_frame = ttk.Frame(self.style_tab, padding="5")
        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        ttk.Label(left_frame, text="段落列表:").pack(anchor=tk.W, pady=5)
        
        self.paragraph_listbox = tk.Listbox(left_frame, font=("SimHei", 10))
        self.paragraph_listbox.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 绑定列表框选择事件
        self.paragraph_listbox.bind('<<ListboxSelect>>', self.on_paragraph_select)
        
        # 创建右侧样式修改区域
        right_frame = ttk.Frame(self.style_tab, padding="5")
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        
        style_frame = ttk.LabelFrame(right_frame, text="段落样式设置", padding="5")
        style_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 字体名称
        ttk.Label(style_frame, text="字体名称:").grid(row=0, column=0, sticky=tk.W, pady=5, padx=5)
        self.font_name_entry = ttk.Entry(style_frame, font=("SimHei", 10))
        self.font_name_entry.grid(row=0, column=1, sticky=tk.W+tk.E, pady=5, padx=5)
        
        # 字体大小
        ttk.Label(style_frame, text="字体大小:").grid(row=1, column=0, sticky=tk.W, pady=5, padx=5)
        self.font_size_var = tk.StringVar()
        self.font_size_combo = ttk.Combobox(style_frame, textvariable=self.font_size_var, font=("SimHei", 10))
        self.font_size_combo['values'] = tuple(range(8, 73, 2))
        self.font_size_combo.grid(row=1, column=1, sticky=tk.W+tk.E, pady=5, padx=5)
        
        # 字体样式
        ttk.Label(style_frame, text="字体样式:").grid(row=2, column=0, sticky=tk.W, pady=5, padx=5)
        style_check_frame = ttk.Frame(style_frame)
        style_check_frame.grid(row=2, column=1, sticky=tk.W, pady=5, padx=5)
        
        self.bold_var = tk.BooleanVar()
        self.italic_var = tk.BooleanVar()
        self.underline_var = tk.BooleanVar()
        
        ttk.Checkbutton(style_check_frame, text="粗体", variable=self.bold_var).pack(side=tk.LEFT, padx=5)
        ttk.Checkbutton(style_check_frame, text="斜体", variable=self.italic_var).pack(side=tk.LEFT, padx=5)
        ttk.Checkbutton(style_check_frame, text="下划线", variable=self.underline_var).pack(side=tk.LEFT, padx=5)
        
        # 设置列权重
        style_frame.columnconfigure(1, weight=1)
        
        # 更新样式按钮
        self.update_style_btn = ttk.Button(right_frame, text="更新样式", command=self.update_style, state=tk.DISABLED)
        self.update_style_btn.pack(side=tk.BOTTOM, pady=20)
    
    def select_file(self):
        """选择Word文档"""
        file_path = filedialog.askopenfilename(
            title="选择Word文档",
            filetypes=[("Word文档", "*.docx")]
        )
        
        if file_path:
            self.input_file = file_path
            self.file_path_var.set(file_path)
            self.process_file_btn.config(state=tk.NORMAL)
            self.preview_btn.config(state=tk.NORMAL)
            
            # 加载文档段落
            self.load_document_paragraphs()
    
    def load_document_paragraphs(self):
        """加载文档中的所有段落"""
        try:
            doc = Document(self.input_file)
            self.paragraphs_text.delete(1.0, tk.END)
            self.paragraph_listbox.delete(0, tk.END)
            
            # 存储所有段落文本
            self.all_paragraphs = []
            
            for i, paragraph in enumerate(doc.paragraphs):
                text = paragraph.text.strip()
                if text:
                    self.all_paragraphs.append(text)
                    self.paragraphs_text.insert(tk.END, f"段落 {i+1}: {text}\n\n")
                    self.paragraph_listbox.insert(tk.END, f"段落 {i+1}: {text[:30]}...")
        except Exception as e:
            messagebox.showerror("错误", f"加载文档失败: {str(e)}")
    
    def preview_pinyin(self):
        """预览拼音（只显示带拼音的版本）"""
        try:
            doc = Document(self.input_file)
            self.paragraphs_text.delete(1.0, tk.END)
            
            # 收集所有字符（包括非多音字），按顺序存储并保留重复字符
            self.all_chars_list = []  # 使用列表保存字符顺序
            self.all_chars = {}  # 用于快速查找拼音选项
            
            # 字符索引，用于生成字符ID
            char_index = 0
            
            for i, paragraph in enumerate(doc.paragraphs):
                text = paragraph.text.strip()
                if text:
                    # 获取拼音预览
                    text_with_pinyin = self.wp.get_text_with_pinyin(text)
                    
                    # 构建拼音预览文本
                    pinyin_preview = f"段落 {i+1}: "
                    for item in text_with_pinyin:
                        if item['is_chinese']:
                            # 生成字符ID
                            char_id = f"{item['char']}_{char_index}"
                            
                            # 检查是否有自定义拼音映射
                            selected_pinyin = item['selected_pinyin']
                            if hasattr(self, 'custom_pinyin_map') and char_id in self.custom_pinyin_map:
                                selected_pinyin = self.custom_pinyin_map[char_id]
                            elif hasattr(self, 'custom_pinyin_map') and item['char'] in self.custom_pinyin_map:
                                selected_pinyin = self.custom_pinyin_map[item['char']]
                            
                            pinyin_preview += f"{item['char']}[{selected_pinyin}] "
                            
                            # 收集所有字符，保留顺序和重复
                            self.all_chars_list.append({
                                'char': item['char'],
                                'pinyins': item['pinyins'],
                                'selected_pinyin': selected_pinyin
                            })
                            
                            # 用于快速查找拼音选项
                            if item['char'] not in self.all_chars:
                                self.all_chars[item['char']] = item['pinyins']
                            
                            # 增加字符索引
                            char_index += 1
                        else:
                            pinyin_preview += item['char']
                    
                    self.paragraphs_text.insert(tk.END, f"{pinyin_preview}\n\n")
            
            # 更新字符列表
            self.update_char_list()
            
            # 更新段落样式列表
            self.update_paragraph_style_list()
        except Exception as e:
            messagebox.showerror("错误", f"预览拼音失败: {str(e)}")
    
    def update_char_list(self):
        """更新字符列表，使用单选框展示，按文本顺序显示并显示字和拼音，重复字符重复出现"""
        # 清空现有内容
        for widget in self.char_content_frame.winfo_children():
            widget.destroy()
        
        # 创建单选框
        row = 0
        col = 0
        max_cols = 5  # 每行最多显示5个字符，因为需要显示拼音
        
        # 使用字典保存字符ID到字符信息的映射
        self.char_id_map = {}
        
        for i, char_info in enumerate(self.all_chars_list):
            char = char_info['char']
            selected_pinyin = char_info['selected_pinyin']
            
            # 为每个字符创建唯一ID
            char_id = f"{char}_{i}"
            self.char_id_map[char_id] = char_info
            
            # 显示字符和当前拼音
            display_text = f"{char}[{selected_pinyin}]"
            
            # 创建单选框
            rb = ttk.Radiobutton(
                self.char_content_frame, 
                text=display_text, 
                variable=self.char_var, 
                value=char_id, 
                command=self.on_char_select
            )
            rb.grid(row=row, column=col, padx=5, pady=5, sticky=tk.W)
            
            # 更新行列
            col += 1
            if col >= max_cols:
                col = 0
                row += 1
        
        # 启用更新按钮
        self.update_pinyin_btn.config(state=tk.NORMAL)
        
        # 重置进度条
        if hasattr(self, 'progress_var'):
            self.progress_var.set(0)
            self.current_play_index = 0
    
    def update_paragraph_style_list(self):
        """更新段落样式列表"""
        self.paragraph_listbox.delete(0, tk.END)
        for i, text in enumerate(self.all_paragraphs):
            self.paragraph_listbox.insert(tk.END, f"段落 {i+1}: {text[:30]}...")
    
    def on_char_select(self):
        """处理字符选择事件"""
        char_id = self.char_var.get()
        if not char_id or char_id not in self.char_id_map:
            return
        
        # 获取字符信息
        char_info = self.char_id_map[char_id]
        self.current_char = char_info['char']
        self.current_char_id = char_id
        
        # 更新拼音下拉框
        self.pinyin_combobox['values'] = char_info['pinyins']
        if char_info['pinyins']:
            # 尝试找到当前选中的拼音的索引
            try:
                current_index = char_info['pinyins'].index(char_info['selected_pinyin'])
                self.pinyin_combobox.current(current_index)
            except ValueError:
                self.pinyin_combobox.current(0)
        
        # 显示当前拼音
        self.custom_pinyin_entry.delete(0, tk.END)
        self.custom_pinyin_entry.insert(0, char_info['selected_pinyin'])
    
    def on_paragraph_select(self, event):
        """处理段落选择事件，预设段落的当前信息"""
        selection = self.paragraph_listbox.curselection()
        if not selection:
            return
        
        index = selection[0]
        self.current_paragraph_index = index
        
        # 启用更新按钮
        self.update_style_btn.config(state=tk.NORMAL)
        
        # 尝试从文档中获取段落的当前样式信息
        try:
            doc = Document(self.input_file)
            paragraphs = [p for p in doc.paragraphs if p.text.strip()]
            if index < len(paragraphs):
                paragraph = paragraphs[index]
                
                # 如果有自定义样式，优先使用自定义样式
                if index in self.paragraph_styles:
                    style = self.paragraph_styles[index]
                    if 'font_name' in style:
                        self.font_name_entry.delete(0, tk.END)
                        self.font_name_entry.insert(0, style['font_name'])
                    else:
                        # 从文档中获取字体名称
                        if paragraph.runs and paragraph.runs[0].font.name:
                            self.font_name_entry.delete(0, tk.END)
                            self.font_name_entry.insert(0, paragraph.runs[0].font.name)
                        else:
                            self.font_name_entry.delete(0, tk.END)
                            
                    if 'font_size' in style:
                        self.font_size_var.set(style['font_size'])
                    else:
                        # 从文档中获取字体大小
                        if paragraph.runs and paragraph.runs[0].font.size:
                            self.font_size_var.set(int(paragraph.runs[0].font.size.pt))
                        else:
                            self.font_size_var.set('')
                            
                    if 'font_bold' in style:
                        self.bold_var.set(style['font_bold'])
                    else:
                        # 从文档中获取粗体设置
                        if paragraph.runs and paragraph.runs[0].font.bold is not None:
                            self.bold_var.set(paragraph.runs[0].font.bold)
                        else:
                            self.bold_var.set(False)
                            
                    if 'font_italic' in style:
                        self.italic_var.set(style['font_italic'])
                    else:
                        # 从文档中获取斜体设置
                        if paragraph.runs and paragraph.runs[0].font.italic is not None:
                            self.italic_var.set(paragraph.runs[0].font.italic)
                        else:
                            self.italic_var.set(False)
                            
                    if 'font_underline' in style:
                        self.underline_var.set(style['font_underline'])
                    else:
                        # 从文档中获取下划线设置
                        if paragraph.runs and paragraph.runs[0].font.underline is not None:
                            self.underline_var.set(paragraph.runs[0].font.underline)
                        else:
                            self.underline_var.set(False)
                else:
                    # 直接从文档中获取样式信息
                    if paragraph.runs and paragraph.runs[0].font.name:
                        self.font_name_entry.delete(0, tk.END)
                        self.font_name_entry.insert(0, paragraph.runs[0].font.name)
                    else:
                        self.font_name_entry.delete(0, tk.END)
                        
                    if paragraph.runs and paragraph.runs[0].font.size:
                        self.font_size_var.set(int(paragraph.runs[0].font.size.pt))
                    else:
                        self.font_size_var.set('')
                        
                    if paragraph.runs and paragraph.runs[0].font.bold is not None:
                        self.bold_var.set(paragraph.runs[0].font.bold)
                    else:
                        self.bold_var.set(False)
                        
                    if paragraph.runs and paragraph.runs[0].font.italic is not None:
                        self.italic_var.set(paragraph.runs[0].font.italic)
                    else:
                        self.italic_var.set(False)
                        
                    if paragraph.runs and paragraph.runs[0].font.underline is not None:
                        self.underline_var.set(paragraph.runs[0].font.underline)
                    else:
                        self.underline_var.set(False)
        except Exception as e:
            # 如果获取文档样式失败，清空输入框
            self.font_name_entry.delete(0, tk.END)
            self.font_size_var.set('')
            self.bold_var.set(False)
            self.italic_var.set(False)
            self.underline_var.set(False)
            print(f"获取段落样式失败: {str(e)}")
    
    def update_pinyin(self):
        """更新字符的拼音"""
        if not hasattr(self, 'current_char_id') or not self.current_char_id:
            messagebox.showwarning("警告", "请先选择一个字符")
            return
        
        # 根据用户选择的拼音来源获取拼音
        pinyin_source = self.pinyin_source_var.get()
        
        if pinyin_source == "preset":
            # 使用预设拼音
            selected_pinyin = self.pinyin_combobox.get()
            if not selected_pinyin:
                messagebox.showwarning("警告", "请从预设拼音中选择一个")
                return
        else:
            # 使用自定义拼音
            selected_pinyin = self.custom_pinyin_entry.get().strip()
            if not selected_pinyin:
                messagebox.showwarning("警告", "请输入自定义拼音")
                return
        
        # 获取当前字符信息
        if self.current_char_id in self.char_id_map:
            char_info = self.char_id_map[self.current_char_id]
            char = char_info['char']
            
            # 更新自定义拼音映射，使用字符ID作为键，确保可以为相同字符的不同位置设置不同拼音
            self.custom_pinyin_map[self.current_char_id] = selected_pinyin
        else:
            # 回退到使用字符作为键
            self.custom_pinyin_map[self.current_char] = selected_pinyin
        
        # 重新预览拼音
        self.preview_pinyin()
        
        messagebox.showinfo("成功", f"已更新 '{self.current_char}' 的拼音")
    
    def update_style(self):
        """更新段落样式"""
        if self.current_paragraph_index < 0:
            messagebox.showwarning("警告", "请先选择一个段落")
            return
        
        # 创建样式字典
        style = {}
        
        # 获取字体名称
        font_name = self.font_name_entry.get().strip()
        if font_name:
            style['font_name'] = font_name
        
        # 获取字体大小
        font_size = self.font_size_var.get()
        if font_size:
            try:
                style['font_size'] = int(font_size)
            except ValueError:
                messagebox.showwarning("警告", "字体大小必须是数字")
                return
        
        # 获取字体样式
        style['font_bold'] = self.bold_var.get()
        style['font_italic'] = self.italic_var.get()
        style['font_underline'] = self.underline_var.get()
        
        # 保存样式
        self.paragraph_styles[self.current_paragraph_index] = style
        
        messagebox.showinfo("成功", f"已更新段落 {self.current_paragraph_index+1} 的样式")
    
    def start_playback(self):
        """开始播放拼音"""
        if not hasattr(self, 'all_chars_list') or not self.all_chars_list:
            messagebox.showwarning("警告", "请先预览拼音以加载字符列表")
            return
        
        # 如果已经在播放，则先停止
        if self.is_playing:
            self.pause_playback()
        
        # 重置播放状态
        self.is_playing = True
        self.start_btn.config(state=tk.DISABLED)
        self.pause_btn.config(state=tk.NORMAL)
        
        # 启动播放线程
        self.play_thread = threading.Thread(target=self._play_pinyin)
        self.play_thread.daemon = True
        self.play_thread.start()
    
    def pause_playback(self):
        """暂停播放拼音"""
        self.is_playing = False
        if self.play_thread:
            self.play_thread.join(timeout=1.0)  # 等待线程结束
        
        self.start_btn.config(state=tk.NORMAL)
        self.pause_btn.config(state=tk.DISABLED)
    
    def _play_pinyin(self):
        """在单独线程中播放拼音"""
        total_chars = len(self.all_chars_list)
        
        while self.is_playing and self.current_play_index < total_chars:
            # 获取当前字符信息
            char_info = self.all_chars_list[self.current_play_index]
            char = char_info['char']
            char_id = f"{char}_{self.current_play_index}"
            
            # 检查是否有自定义拼音映射
            selected_pinyin = char_info['selected_pinyin']
            if char_id in self.custom_pinyin_map:
                selected_pinyin = self.custom_pinyin_map[char_id]
            elif char in self.custom_pinyin_map:
                selected_pinyin = self.custom_pinyin_map[char]
            
            # 在UI线程中选中当前字符
            self.root.after(0, lambda cid=char_id: self._select_char(cid))
            
            # 播放拼音
            if selected_pinyin:
                self.engine.say(selected_pinyin)
                time.sleep(0.8)
                self.engine.runAndWait()
            
            # 更新进度条
            progress = (self.current_play_index + 1) / total_chars * 100
            self.root.after(0, lambda p=progress: self.progress_var.set(p))
            
            # 移动到下一个字符
            self.current_play_index += 1
        
        # 播放完成
        if self.is_playing:
            self.root.after(0, self.pause_playback)
    
    def _select_char(self, char_id):
        """在UI线程中选中指定的字符"""
        self.char_var.set(char_id)
        self.on_char_select()
    
    def process_file(self):
        """处理文档并保存"""
        try:
            # 让用户选择保存路径
            save_path = filedialog.asksaveasfilename(
                title="保存带拼音的文档",
                defaultextension=".docx",
                filetypes=[("Word文档", "*.docx")]
            )
            
            if save_path:
                # 处理文档
                self.output_file = self.wp.process_document(
                    self.input_file, 
                    save_path, 
                    self.custom_pinyin_map,
                    self.paragraph_styles
                )
                
                messagebox.showinfo("成功", f"文档已成功处理并保存至:\n{self.output_file}")
        except Exception as e:
            messagebox.showerror("错误", f"处理文档失败: {str(e)}")

if __name__ == "__main__":
    # 创建主窗口
    root = tk.Tk()
    # 设置中文字体支持
    root.option_add("*Font", "SimHei 10")
    # 创建应用实例
    app = PinyinApp(root)
    # 运行主循环
    root.mainloop()